package com.huwei.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


public class ClassFileUtil {
	
	static public Set<Class<?>> getClasses(String packageName ,boolean isRecursive){
		Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
		String packageName0 = packageName;
		String packageDirName = packageName0.replace('.', '/');
		Enumeration<URL> dirs;
		try {
			dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
			while (dirs.hasMoreElements()) {
				URL url = dirs.nextElement();
				String protocol = url.getProtocol();
				if ("file".equals(protocol)) {
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
					findAndAddClassesInPackageByFile(packageName0, filePath, isRecursive, classes);
				} else if (protocol.equals("vfsfile")) {
					String cleanURL = url.toString();
					cleanURL = cleanURL.replaceFirst("vfsfile:", "file:");
					cleanURL = cleanURL.replaceFirst("\\.jar/", ".jar!/");
					String filePath = URLDecoder.decode((new URL(cleanURL)).getFile(), "UTF-8");
					findAndAddClassesInPackageByFile(packageName0, filePath, isRecursive, classes);
				} else if ("jar".equals(protocol) || "zip".equals(protocol)) {
					try {
						@SuppressWarnings("resource")
						JarFile jar = new JarFile(new File(url.getFile().replace("!/" + packageDirName, "")));
						Enumeration<JarEntry> entries = jar.entries();
						while (entries.hasMoreElements()) {
							JarEntry entry = entries.nextElement();
							String name = entry.getName();
							if (name.charAt(0) == '/') {
								name = name.substring(1);
							}
							if (name.startsWith(packageDirName)) {
								int idx = name.lastIndexOf('/');
								if (idx != -1) {
									packageName0 = name.substring(0, idx).replace('/', '.');
								}
								if ((idx != -1) || isRecursive) {
									if (name.endsWith(".class") && !entry.isDirectory()) {
										String className = name.substring(packageName0.length() + 1, name.length() - 6);
										try {
											classes.add(Class.forName(packageName0 + '.' + className));
										} catch (ClassNotFoundException e) {
											e.printStackTrace();
										}
									}
								}
							}
						}
					} catch (Exception e1) {
						e1.printStackTrace();
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return classes;
	}
	
	public static Set<Class<?>> getClasses(String packageName) {
		return getClasses(packageName, false);
	}

	private static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,
			Set<Class<?>> classes) {
		File dir = new File(packagePath);
		if (!dir.exists() || !dir.isDirectory()) {
			return;
		}
		File[] dirfiles = dir.listFiles(new FileFilter() {
			public boolean accept(File file) {
				return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
			}
		});
		for (File file : dirfiles) {
			if (file.isDirectory()) {
				findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,
						classes);
			} else {
				String className = file.getName().substring(0, file.getName().length() - 6);
				try {
					classes.add(
							Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
				} catch (ClassNotFoundException e) {
				}
			}
		}
	}
}
